package com.shoulder.boot.acl.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shoulder.boot.acl.dto.M2rDTO;
import com.shoulder.boot.acl.dto.RoleAddDTO;
import com.shoulder.boot.acl.dto.RoleModDTO;
import com.shoulder.boot.acl.dto.RoleQueryDTO;
import com.shoulder.boot.acl.entity.Role;
import com.shoulder.boot.acl.entity.RoleMenu;
import com.shoulder.boot.acl.exception.AclException;
import com.shoulder.boot.acl.mapper.RoleMapper;
import com.shoulder.boot.acl.mapper.RoleMenuMapper;
import com.shoulder.boot.acl.service.RoleService;
import com.shoulder.boot.acl.utils.RoleUtils;
import com.shoulder.boot.acl.vo.RoleVo;
import com.shoulder.core.api.Kv;
import com.shoulder.core.enums.ScopeAuthEnums;
import com.shoulder.core.fetch.BaseIds;
import com.shoulder.core.utils.TokenUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import static com.shoulder.boot.acl.entity.Role.TENANT_ONLY_YES;

/**
 * 角色信息 服务实现类
 *
 * @author 596767880@qq.com
 * @since 2024-03-14 11:56:27
 */
@Service
@Transactional
@AllArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    private final RoleMenuMapper roleMenuMapper;

    @Override
    public List<RoleVo> listQuery(RoleQueryDTO queryDTO) {
        List<Role> list = this.baseMapper.selectList(RoleUtils.buildQueryWrapper(queryDTO));
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return RoleUtils.buildUtils().toVos(list);
    }

    @Override
    public RoleVo look(String id) {
        Role entity = this.baseMapper.selectById(id);
        if (ObjectUtils.isEmpty(entity)) {
            throw new AclException("数据不存在");
        }
        return RoleUtils.buildUtils().toVo(entity);
    }

    @Override
    public List<RoleVo> looks(BaseIds<String> baseIds) {
        List<Role> list = this.baseMapper.selectBatchIds(baseIds.getIds());
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return RoleUtils.buildUtils().toVos(list);
    }

    @Override
    public void del(String id) {
        roleMenuMapper.delete(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, id));
        this.baseMapper.deleteById(id);
    }

    @Override
    public void batchDel(BaseIds<String> baseIds) {
        this.baseMapper.deleteBatchIds(baseIds.getIds());
    }


    @Override
    public Page<RoleVo> pageQuery(RoleQueryDTO queryDTO) {
        Page<Role> selectPage = this.baseMapper.selectPage(new Page<>(queryDTO.getCurrent(), queryDTO.getSize()),
                RoleUtils.buildQueryWrapper(queryDTO));
        if (selectPage == null || CollectionUtils.isEmpty(selectPage.getRecords())) {
            return new Page<>();
        }
        return RoleUtils.buildUtils().toPage(selectPage);
    }

    @Override
    public void mod(RoleModDTO modDTO) {
        Role info = Optional.ofNullable(this.baseMapper.selectById(modDTO.getId())).orElseThrow(() -> new AclException("角色信息不存在"));
        Role role = this.baseMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getCode, modDTO.getCode())
                .eq(Role::getTenantId, TokenUtils.parseUser().getTenantId())
                .ne(Role::getId, modDTO.getId()));
        if (role != null) {
            throw new AclException("角色编码已存在");
        }
        BeanUtils.copyProperties(modDTO, info);
        this.baseMapper.updateById(info);
    }

    @Override
    public void add(RoleAddDTO addDTO) {
        Role info = this.baseMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getCode, addDTO.getCode())
                .eq(Role::getTenantId, TokenUtils.parseUser().getTenantId()));
        if (!ObjectUtils.isEmpty(info)) {
            throw new AclException("角色编码已存在");
        }
        info = new Role();
        info.setTenantId(TokenUtils.parseUser().getTenantId());
        BeanUtils.copyProperties(addDTO, info);
        this.baseMapper.insert(info);
    }

    @Override
    public void switchRole(String id) {
        // 如果角色被禁用，则启用，反之亦然
        Role role = this.baseMapper.selectById(id);
        if (ObjectUtils.isEmpty(role)) {
            throw new AclException("角色不存在");
        }
        role.setTenantOnly(TENANT_ONLY_YES == role.getTenantOnly() ? Role.TENANT_ONLY_NO : TENANT_ONLY_YES);
        this.baseMapper.updateById(role);
    }

    @Override
    public void m2r(M2rDTO m2rDTO) {
        //判断角色是否存在
        Role role = this.baseMapper.selectById(m2rDTO.getRoleId());
        if (ObjectUtils.isEmpty(role)) {
            throw new AclException("角色不存在");
        }
        // 先删除原有关系
        roleMenuMapper.delete(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, m2rDTO.getRoleId()));
        if (!CollectionUtils.isEmpty(m2rDTO.getMenuIds())) {
            m2rDTO.getMenuIds().forEach(menuId -> {
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setRoleId(m2rDTO.getRoleId());
                roleMenu.setMenuId(menuId);
                roleMenuMapper.insert(roleMenu);
            });
        }
    }

    @Override
    public List<String> roleMenus(String id) {
        // 判断角色是否存在 不存在抛出异常
        Role role = this.baseMapper.selectById(id);
        if (ObjectUtils.isEmpty(role)) {
            throw new AclException("角色不存在");
        }
        // 查询角色菜单关系
        List<RoleMenu> roleMenus = roleMenuMapper.selectList(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, id));
        if (CollectionUtils.isEmpty(roleMenus)) {
            return Collections.emptyList();
        }
        // 取出菜单id
        return roleMenus.stream().map(RoleMenu::getMenuId).toList();
    }

    @Override
    public List<Role> tenantRoles() {
        return this.baseMapper.selectList(new LambdaQueryWrapper<Role>()
                .orderByDesc(Role::getCreateTime).eq(Role::getTenantOnly, TENANT_ONLY_YES));
    }

    @Override
    public List<Kv> scopeEnums() {
        List<Kv> list = new ArrayList<>();
        for (ScopeAuthEnums value : ScopeAuthEnums.values()) {
            Kv kv = new Kv();
            kv.setValue(value.getScope());
            kv.setKey(value.getLabel());
            list.add(kv);
        }
        return list;
    }
}